"use server" /** * 사적이고 우회적인 요청사항... -- readonly 사용자 생성 (비밀번호 설정) CREATE USER readonly WITH PASSWORD 'tempReadOnly_123'; -- evcp 데이터베이스에 연결할 수 있는 권한 부여 GRANT CONNECT ON DATABASE evcp TO readonly; -- 조회할 스키마 사용 권한 부여 GRANT USAGE ON SCHEMA public TO readonly; GRANT USAGE ON SCHEMA soap TO readonly; GRANT USAGE ON SCHEMA nonsap TO readonly; GRANT USAGE ON SCHEMA mdg TO readonly; -- 기존 모든 테이블에 대한 SELECT 권한 부여 GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly; GRANT SELECT ON ALL TABLES IN SCHEMA soap TO readonly; GRANT SELECT ON ALL TABLES IN SCHEMA nonsap TO readonly; GRANT SELECT ON ALL TABLES IN SCHEMA mdg TO readonly; */ import { Pool } from "pg" export interface QueryResultState { columns: string[] // eslint-disable-next-line @typescript-eslint/no-explicit-any rows: Record[] error?: string } export async function executeSqlAction( prevState: QueryResultState, formData: FormData ): Promise { const query = (formData.get("query") as string | null) ?? "" if (!query.trim()) { return { ...prevState, error: "쿼리를 입력해주세요." } } try { const connectionString = process.env.READONLY_DB_URL if (!connectionString) { return { ...prevState, error: "READONLY_DB_URL 환경변수가 설정되지 않았습니다." } } const pool = new Pool({ connectionString }) const result = await pool.query(query) await pool.end() return { columns: result.fields.map((f) => f.name), // eslint-disable-next-line @typescript-eslint/no-explicit-any rows: result.rows as Record[], } } catch (err) { return { ...prevState, error: (err as Error).message } } }